window.mfox &&
  window.mfox.use(() => {
    const oForEach = function (target, callback) {
      Object.keys(target).forEach(
        (n) =>
          !/oForEach|oFilter/.test(n) &&
          callback.call(target, target[n], n, target)
      );
      return target;
    };
    const oFilter = function (target, callback) {
      let _target = {};
      Object.keys(target).forEach((n) => {
        const res = callback.call(target, target[n], n, target);
        if (res) {
          _target[n] = target[n];
        }
      });
      return _target;
    };
    const splitSelectorToCommands = (selector) => {
      let from = selector[0];
      from = /select\s+(.+)\s+from\s+(.+)\s+source\s+(.+)\s*/.exec(from);
      const fromAttr = from[1];
      const fromTable = from[2];
      const fromStore = from[3].split(/\s+and\s+/);
      let to = selector[1];
      if (to) {
        to = to.split(/\s+and\s+/);
        to.forEach((item, index) => {
          to[index] = item
            .replace(/\s+or\s+/gim, " || ")
            .replace(/\s+=\s+/gim, " === ");
        });
      }
      return {
        fromTable,
        fromAttr,
        fromStore,
        to,
      };
    };
    const upperFirst = (str) => {
      str = str.toLowerCase();
      str = str.substr(0, 1).toUpperCase() + str.substr(1, str.length - 1);
      return str;
    };

    const fromAttrFilter = (to, obj, table) => {
      let storeResult = {};
      to.forEach((item) => {
        const filterObj = oFilter(obj, (value, name) =>
          new Function(table, "return " + item)({
            [name]: value,
          })
        );
        storeResult = Object.assign(storeResult, filterObj);
      });
      return storeResult;
    };

    const fromAttrFilterFns = (fromTable, fromAttr, callback, target) => {
      let storeResult = {};
      !storeResult[fromTable] && (storeResult[fromTable] = {});
      const obj = target["map" + upperFirst(fromTable)](fromAttr.split(","));
      oForEach(obj, (value, name) => {
        obj[name] = callback;
      });
      storeResult[fromTable] = obj;
      return storeResult;
    };

    const mixinsData = (fromTable, fromAttr, name, target) => {
      let storeResult = {};
      switch (fromTable) {
        case "state":
          !storeResult.state && (storeResult.state = {});
          storeResult.state = target["map" + upperFirst(fromTable)](
            fromAttr.split(",")
          );
          break;
        case "actions":
        case "mutations":
        case "getters":
          storeResult = Object.assign(
            storeResult,
            fromAttrFilterFns(
              fromTable,
              fromAttr,
              (v) => {
                return target[
                  fromTable === "actions"
                    ? "dispatch"
                    : fromTable === "getters"
                    ? "computed"
                    : "commit"
                ](name, v);
              },
              target
            )
          );
          break;
      }
      return storeResult;
    };

    const queryStoreState = (selector, target) => {
      const { fromAttr, fromTable, fromStore, to } =
        splitSelectorToCommands(selector);
      let result = [];
      if (fromStore) {
        fromStore.forEach((store) => {
          const res = target.hasModule(store.replace(/['"]+/gim, ""));
          if (res && res.length > 0) {
            let storeResult = {};
            if (fromAttr) {
              res.forEach((r) => {
                switch (fromAttr) {
                  case "*":
                    if (to) {
                      storeResult = Object.assign(
                        storeResult,
                        fromAttrFilter(to, r[fromTable], fromTable)
                      );
                    } else {
                      oForEach(r[fromTable], (value, name) => {
                        storeResult = Object.assign(
                          storeResult,
                          mixinsData(fromTable, fromAttr, name, target)
                        );
                      });
                    }
                    result.push(storeResult);
                    break;
                  default:
                    const obj = new Function(
                      fromTable,
                      "const {" +
                        fromAttr +
                        "} = " +
                        fromTable +
                        "; return {" +
                        fromAttr +
                        "}"
                    )(r[fromTable]);
                    if (to) {
                      storeResult = Object.assign(
                        storeResult,
                        fromAttrFilter(to, obj, fromTable)
                      );
                    } else {
                      oForEach(r[fromTable], (value, name) => {
                        if (fromAttr.split(",").includes(name)) {
                          storeResult = Object.assign(
                            storeResult,
                            mixinsData(fromTable, fromAttr, name, target)
                          );
                        }
                      });
                    }
                    result.push(storeResult);
                    break;
                }
              });
            }
          }
        });
      }
      return result;
    };
    return {
      query(selector) {
        selector = selector.split("where");
        return queryStoreState(selector, this);
      },
    };
  });
